/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* vim: set ts=8 sts=2 et sw=2 tw=80: *//* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#include"AccessCheck.h"#include"base/basictypes.h"#include"ipc/IPCMessageUtils.h"#include"mozilla/dom/Event.h"#include"mozilla/dom/ShadowRoot.h"#include"mozilla/ContentEvents.h"#include"mozilla/DOMEventTargetHelper.h"#include"mozilla/EventStateManager.h"#include"mozilla/InternalMutationEvent.h"#include"mozilla/dom/Performance.h"#include"mozilla/MiscEvents.h"#include"mozilla/MouseEvents.h"#include"mozilla/Preferences.h"#include"mozilla/TextEvents.h"#include"mozilla/TouchEvents.h"#include"nsContentUtils.h"#include"nsCOMPtr.h"#include"nsDeviceContext.h"#include"nsError.h"#include"nsGlobalWindow.h"#include"nsIFrame.h"#include"nsIContent.h"#include"nsIDocument.h"#include"nsIPresShell.h"#include"nsIScrollableFrame.h"#include"nsJSEnvironment.h"#include"nsLayoutUtils.h"#include"nsPIWindowRoot.h"#include"nsRFPService.h"#include"WorkerPrivate.h"namespacemozilla{namespacedom{staticchar*sPopupAllowedEvents;staticboolsReturnHighResTimeStamp=false;staticboolsReturnHighResTimeStampIsSet=false;Event::Event(EventTarget*aOwner,nsPresContext*aPresContext,WidgetEvent*aEvent){ConstructorInit(aOwner,aPresContext,aEvent);}Event::Event(nsPIDOMWindowInner*aParent){ConstructorInit(nsGlobalWindow::Cast(aParent),nullptr,nullptr);}voidEvent::ConstructorInit(EventTarget*aOwner,nsPresContext*aPresContext,WidgetEvent*aEvent){SetOwner(aOwner);mIsMainThreadEvent=NS_IsMainThread();if(mIsMainThreadEvent&&!sReturnHighResTimeStampIsSet){Preferences::AddBoolVarCache(&sReturnHighResTimeStamp,"dom.event.highrestimestamp.enabled",sReturnHighResTimeStamp);sReturnHighResTimeStampIsSet=true;}mPrivateDataDuplicated=false;mWantsPopupControlCheck=false;if(aEvent){mEvent=aEvent;mEventIsInternal=false;}else{mEventIsInternal=true;/* A derived class might want to allocate its own type of aEvent (derived from WidgetEvent). To do this, it should take care to pass a non-nullptr aEvent to this ctor, e.g.: FooEvent::FooEvent(..., WidgetEvent* aEvent) : Event(..., aEvent ? aEvent : new WidgetEvent()) Then, to override the mEventIsInternal assignments done by the base ctor, it should do this in its own ctor: FooEvent::FooEvent(..., WidgetEvent* aEvent) ... { ... if (aEvent) { mEventIsInternal = false; } else { mEventIsInternal = true; } ... } */mEvent=newWidgetEvent(false,eVoidEvent);mEvent->mTime=PR_Now();}InitPresContextData(aPresContext);}voidEvent::InitPresContextData(nsPresContext*aPresContext){mPresContext=aPresContext;// Get the explicit original target (if it's anonymous make it null){nsCOMPtr<nsIContent>content=GetTargetFromFrame();mExplicitOriginalTarget=content;if(content&&content->IsInAnonymousSubtree()){mExplicitOriginalTarget=nullptr;}}}Event::~Event(){NS_ASSERT_OWNINGTHREAD(Event);if(mEventIsInternal&&mEvent){deletemEvent;}}NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Event)NS_WRAPPERCACHE_INTERFACE_MAP_ENTRYNS_INTERFACE_MAP_ENTRY(nsISupports)NS_INTERFACE_MAP_ENTRY(nsIDOMEvent)NS_INTERFACE_MAP_ENDNS_IMPL_CYCLE_COLLECTING_ADDREF(Event)NS_IMPL_CYCLE_COLLECTING_RELEASE(Event)NS_IMPL_CYCLE_COLLECTION_CLASS(Event)NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Event)NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPERNS_IMPL_CYCLE_COLLECTION_TRACE_ENDNS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Event)if(tmp->mEventIsInternal){tmp->mEvent->mTarget=nullptr;tmp->mEvent->mCurrentTarget=nullptr;tmp->mEvent->mOriginalTarget=nullptr;switch(tmp->mEvent->mClass){caseeMouseEventClass:caseeMouseScrollEventClass:caseeWheelEventClass:caseeSimpleGestureEventClass:caseePointerEventClass:tmp->mEvent->AsMouseEventBase()->relatedTarget=nullptr;break;caseeDragEventClass:{WidgetDragEvent*dragEvent=tmp->mEvent->AsDragEvent();dragEvent->mDataTransfer=nullptr;dragEvent->relatedTarget=nullptr;break;}caseeClipboardEventClass:tmp->mEvent->AsClipboardEvent()->mClipboardData=nullptr;break;caseeMutationEventClass:tmp->mEvent->AsMutationEvent()->mRelatedNode=nullptr;break;caseeFocusEventClass:tmp->mEvent->AsFocusEvent()->mRelatedTarget=nullptr;break;default:break;}}NS_IMPL_CYCLE_COLLECTION_UNLINK(mPresContext);NS_IMPL_CYCLE_COLLECTION_UNLINK(mExplicitOriginalTarget);NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner);NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPERNS_IMPL_CYCLE_COLLECTION_UNLINK_ENDNS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Event)if(tmp->mEventIsInternal){NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mTarget)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mCurrentTarget)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mOriginalTarget)switch(tmp->mEvent->mClass){caseeMouseEventClass:caseeMouseScrollEventClass:caseeWheelEventClass:caseeSimpleGestureEventClass:caseePointerEventClass:NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,"mEvent->relatedTarget");cb.NoteXPCOMChild(tmp->mEvent->AsMouseEventBase()->relatedTarget);break;caseeDragEventClass:{WidgetDragEvent*dragEvent=tmp->mEvent->AsDragEvent();NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,"mEvent->mDataTransfer");cb.NoteXPCOMChild(dragEvent->mDataTransfer);NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,"mEvent->relatedTarget");cb.NoteXPCOMChild(dragEvent->relatedTarget);break;}caseeClipboardEventClass:NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,"mEvent->mClipboardData");cb.NoteXPCOMChild(tmp->mEvent->AsClipboardEvent()->mClipboardData);break;caseeMutationEventClass:NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,"mEvent->mRelatedNode");cb.NoteXPCOMChild(tmp->mEvent->AsMutationEvent()->mRelatedNode);break;caseeFocusEventClass:NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,"mEvent->mRelatedTarget");cb.NoteXPCOMChild(tmp->mEvent->AsFocusEvent()->mRelatedTarget);break;default:break;}}NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresContext)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExplicitOriginalTarget)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)NS_IMPL_CYCLE_COLLECTION_TRAVERSE_ENDJSObject*Event::WrapObject(JSContext*aCx,JS::Handle<JSObject*>aGivenProto){returnWrapObjectInternal(aCx,aGivenProto);}JSObject*Event::WrapObjectInternal(JSContext*aCx,JS::Handle<JSObject*>aGivenProto){returnEventBinding::Wrap(aCx,this,aGivenProto);}// nsIDOMEventInterfaceNS_IMETHODIMPEvent::GetType(nsAString&aType){if(!mIsMainThreadEvent){aType=mEvent->mSpecifiedEventTypeString;returnNS_OK;}GetWidgetEventType(mEvent,aType);returnNS_OK;}EventTarget*Event::GetTarget()const{returnmEvent->GetDOMEventTarget();}NS_IMETHODIMPEvent::GetTarget(nsIDOMEventTarget**aTarget){NS_IF_ADDREF(*aTarget=GetTarget());returnNS_OK;}EventTarget*Event::GetCurrentTarget()const{returnmEvent->GetCurrentDOMEventTarget();}NS_IMETHODIMPEvent::GetCurrentTarget(nsIDOMEventTarget**aCurrentTarget){NS_IF_ADDREF(*aCurrentTarget=GetCurrentTarget());returnNS_OK;}//// Get the actual event target node (may have been retargeted for mouse events)//already_AddRefed<nsIContent>Event::GetTargetFromFrame(){if(!mPresContext){returnnullptr;}// Get the mTarget frame (have to get the ESM first)nsIFrame*targetFrame=mPresContext->EventStateManager()->GetEventTarget();if(!targetFrame){returnnullptr;}// get the real contentnsCOMPtr<nsIContent>realEventContent;targetFrame->GetContentForEvent(mEvent,getter_AddRefs(realEventContent));returnrealEventContent.forget();}EventTarget*Event::GetExplicitOriginalTarget()const{if(mExplicitOriginalTarget){returnmExplicitOriginalTarget;}returnGetTarget();}NS_IMETHODIMPEvent::GetExplicitOriginalTarget(nsIDOMEventTarget**aRealEventTarget){NS_IF_ADDREF(*aRealEventTarget=GetExplicitOriginalTarget());returnNS_OK;}EventTarget*Event::GetOriginalTarget()const{returnmEvent->GetOriginalDOMEventTarget();}NS_IMETHODIMPEvent::GetOriginalTarget(nsIDOMEventTarget**aOriginalTarget){NS_IF_ADDREF(*aOriginalTarget=GetOriginalTarget());returnNS_OK;}EventTarget*Event::GetComposedTarget()const{EventTarget*et=GetOriginalTarget();nsCOMPtr<nsIContent>content=do_QueryInterface(et);if(!content){returnet;}nsIContent*nonChrome=content->FindFirstNonChromeOnlyAccessContent();returnnonChrome?static_cast<EventTarget*>(nonChrome):static_cast<EventTarget*>(content->GetComposedDoc());}NS_IMETHODIMP_(void)Event::SetTrusted(boolaTrusted){mEvent->mFlags.mIsTrusted=aTrusted;}boolEvent::Init(mozilla::dom::EventTarget*aGlobal){if(!mIsMainThreadEvent){returnworkers::IsCurrentThreadRunningChromeWorker();}booltrusted=false;nsCOMPtr<nsPIDOMWindowInner>w=do_QueryInterface(aGlobal);if(w){nsCOMPtr<nsIDocument>d=w->GetExtantDoc();if(d){trusted=nsContentUtils::IsChromeDoc(d);nsIPresShell*s=d->GetShell();if(s){InitPresContextData(s->GetPresContext());}}}returntrusted;}// staticalready_AddRefed<Event>Event::Constructor(constGlobalObject&aGlobal,constnsAString&aType,constEventInit&aParam,ErrorResult&aRv){nsCOMPtr<mozilla::dom::EventTarget>t=do_QueryInterface(aGlobal.GetAsSupports());returnConstructor(t,aType,aParam);}// staticalready_AddRefed<Event>Event::Constructor(EventTarget*aEventTarget,constnsAString&aType,constEventInit&aParam){RefPtr<Event>e=newEvent(aEventTarget,nullptr,nullptr);booltrusted=e->Init(aEventTarget);e->InitEvent(aType,aParam.mBubbles,aParam.mCancelable);e->SetTrusted(trusted);e->SetComposed(aParam.mComposed);returne.forget();}uint16_tEvent::EventPhase()const{// Note, remember to check that this works also// if or when Bug 235441 is fixed.if((mEvent->mCurrentTarget&&mEvent->mCurrentTarget==mEvent->mTarget)||mEvent->mFlags.InTargetPhase()){returnnsIDOMEvent::AT_TARGET;}if(mEvent->mFlags.mInCapturePhase){returnnsIDOMEvent::CAPTURING_PHASE;}if(mEvent->mFlags.mInBubblingPhase){returnnsIDOMEvent::BUBBLING_PHASE;}returnnsIDOMEvent::NONE;}NS_IMETHODIMPEvent::GetEventPhase(uint16_t*aEventPhase){*aEventPhase=EventPhase();returnNS_OK;}NS_IMETHODIMPEvent::GetBubbles(bool*aBubbles){*aBubbles=Bubbles();returnNS_OK;}NS_IMETHODIMPEvent::GetCancelable(bool*aCancelable){*aCancelable=Cancelable();returnNS_OK;}NS_IMETHODIMPEvent::GetTimeStamp(uint64_t*aTimeStamp){*aTimeStamp=mEvent->mTime;returnNS_OK;}NS_IMETHODIMPEvent::StopPropagation(){mEvent->StopPropagation();returnNS_OK;}NS_IMETHODIMPEvent::StopImmediatePropagation(){mEvent->StopImmediatePropagation();returnNS_OK;}NS_IMETHODIMPEvent::StopCrossProcessForwarding(){mEvent->StopCrossProcessForwarding();returnNS_OK;}NS_IMETHODIMPEvent::GetIsTrusted(bool*aIsTrusted){*aIsTrusted=IsTrusted();returnNS_OK;}NS_IMETHODIMPEvent::PreventDefault(){// This method is called only from C++ code which must handle default action// of this event. So, pass true always.PreventDefaultInternal(true);returnNS_OK;}voidEvent::PreventDefault(JSContext*aCx,CallerTypeaCallerType){// Note that at handling default action, another event may be dispatched.// Then, JS in content mey be call preventDefault()// even in the event is in system event group. Therefore, don't refer// mInSystemGroup here.PreventDefaultInternal(aCallerType==CallerType::System);}voidEvent::PreventDefaultInternal(boolaCalledByDefaultHandler){if(!mEvent->mFlags.mCancelable){return;}if(mEvent->mFlags.mInPassiveListener){nsCOMPtr<nsPIDOMWindowInner>win(do_QueryInterface(mOwner));if(win){if(nsIDocument*doc=win->GetExtantDoc()){nsStringtype;GetType(type);constchar16_t*params[]={type.get()};doc->WarnOnceAbout(nsIDocument::ePreventDefaultFromPassiveListener,false,params,ArrayLength(params));}}return;}mEvent->PreventDefault(aCalledByDefaultHandler);if(!IsTrusted()){return;}WidgetDragEvent*dragEvent=mEvent->AsDragEvent();if(!dragEvent){return;}nsCOMPtr<nsINode>node=do_QueryInterface(mEvent->mCurrentTarget);if(!node){nsCOMPtr<nsPIDOMWindowOuter>win=do_QueryInterface(mEvent->mCurrentTarget);if(!win){return;}node=win->GetExtantDoc();}if(!nsContentUtils::IsChromeDoc(node->OwnerDoc())){dragEvent->mDefaultPreventedOnContent=true;}}voidEvent::SetEventType(constnsAString&aEventTypeArg){if(mIsMainThreadEvent){mEvent->mSpecifiedEventTypeString.Truncate();mEvent->mSpecifiedEventType=nsContentUtils::GetEventMessageAndAtom(aEventTypeArg,mEvent->mClass,&(mEvent->mMessage));mEvent->SetDefaultComposed();}else{mEvent->mSpecifiedEventType=nullptr;mEvent->mMessage=eUnidentifiedEvent;mEvent->mSpecifiedEventTypeString=aEventTypeArg;mEvent->SetComposed(aEventTypeArg);}mEvent->SetDefaultComposedInNativeAnonymousContent();}already_AddRefed<EventTarget>Event::EnsureWebAccessibleRelatedTarget(EventTarget*aRelatedTarget){nsCOMPtr<EventTarget>relatedTarget=aRelatedTarget;if(relatedTarget){nsCOMPtr<nsIContent>content=do_QueryInterface(relatedTarget);nsCOMPtr<nsIContent>currentTarget=do_QueryInterface(mEvent->mCurrentTarget);if(content&&content->ChromeOnlyAccess()&&!nsContentUtils::CanAccessNativeAnon()){content=content->FindFirstNonChromeOnlyAccessContent();relatedTarget=do_QueryInterface(content);}nsIContent*shadowRelatedTarget=GetShadowRelatedTarget(currentTarget,content);if(shadowRelatedTarget){relatedTarget=shadowRelatedTarget;}if(relatedTarget){relatedTarget=relatedTarget->GetTargetForDOMEvent();}}returnrelatedTarget.forget();}voidEvent::InitEvent(constnsAString&aEventTypeArg,boolaCanBubbleArg,boolaCancelableArg){// Make sure this event isn't already being dispatched.NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);if(IsTrusted()){// Ensure the caller is permitted to dispatch trusted DOM events.if(!nsContentUtils::ThreadsafeIsCallerChrome()){SetTrusted(false);}}SetEventType(aEventTypeArg);mEvent->mFlags.mBubbles=aCanBubbleArg;mEvent->mFlags.mCancelable=aCancelableArg;mEvent->mFlags.mDefaultPrevented=false;mEvent->mFlags.mDefaultPreventedByContent=false;mEvent->mFlags.mDefaultPreventedByChrome=false;mEvent->mFlags.mPropagationStopped=false;mEvent->mFlags.mImmediatePropagationStopped=false;// Clearing the old targets, so that the event is targeted correctly when// re-dispatching it.mEvent->mTarget=nullptr;mEvent->mOriginalTarget=nullptr;}NS_IMETHODIMPEvent::DuplicatePrivateData(){NS_ASSERTION(mEvent,"No WidgetEvent for Event duplication!");if(mEventIsInternal){returnNS_OK;}mEvent=mEvent->Duplicate();mPresContext=nullptr;mEventIsInternal=true;mPrivateDataDuplicated=true;returnNS_OK;}NS_IMETHODIMPEvent::SetTarget(nsIDOMEventTarget*aTarget){mEvent->mTarget=do_QueryInterface(aTarget);returnNS_OK;}NS_IMETHODIMP_(bool)Event::IsDispatchStopped(){returnmEvent->PropagationStopped();}NS_IMETHODIMP_(WidgetEvent*)Event::WidgetEventPtr(){returnmEvent;}NS_IMETHODIMP_(Event*)Event::InternalDOMEvent(){returnthis;}// return true if eventName is contained within events, delimited by// spacesstaticboolPopupAllowedForEvent(constchar*eventName){if(!sPopupAllowedEvents){Event::PopupAllowedEventsChanged();if(!sPopupAllowedEvents){returnfalse;}}nsDependentCStringevents(sPopupAllowedEvents);nsCString::const_iteratorstart,end;nsCString::const_iteratorstartiter(events.BeginReading(start));events.EndReading(end);while(startiter!=end){nsCString::const_iteratorenditer(end);if(!FindInReadable(nsDependentCString(eventName),startiter,enditer))returnfalse;// the match is surrounded by spaces, or at a string boundaryif((startiter==start||*--startiter==' ')&&(enditer==end||*enditer==' ')){returntrue;}// Move on and see if there are other matches. (The delimitation// requirement makes it pointless to begin the next search before// the end of the invalid match just found.)startiter=enditer;}returnfalse;}// staticPopupControlStateEvent::GetEventPopupControlState(WidgetEvent*aEvent,nsIDOMEvent*aDOMEvent){// generally if an event handler is running, new windows are disallowed.// check for exceptions:PopupControlStateabuse=openAbused;if(aDOMEvent&&aDOMEvent->InternalDOMEvent()->GetWantsPopupControlCheck()){nsAutoStringtype;aDOMEvent->GetType(type);if(PopupAllowedForEvent(NS_ConvertUTF16toUTF8(type).get())){returnopenAllowed;}}switch(aEvent->mClass){caseeBasicEventClass:// For these following events only allow popups if they're// triggered while handling user input. See// nsPresShell::HandleEventInternal() for details.if(EventStateManager::IsHandlingUserInput()){switch(aEvent->mMessage){caseeFormSelect:if(PopupAllowedForEvent("select")){abuse=openControlled;}break;caseeFormChange:if(PopupAllowedForEvent("change")){abuse=openControlled;}break;default:break;}}break;caseeEditorInputEventClass:// For this following event only allow popups if it's triggered// while handling user input. See// nsPresShell::HandleEventInternal() for details.if(EventStateManager::IsHandlingUserInput()){switch(aEvent->mMessage){caseeEditorInput:if(PopupAllowedForEvent("input")){abuse=openControlled;}break;default:break;}}break;caseeInputEventClass:// For this following event only allow popups if it's triggered// while handling user input. See// nsPresShell::HandleEventInternal() for details.if(EventStateManager::IsHandlingUserInput()){switch(aEvent->mMessage){caseeFormChange:if(PopupAllowedForEvent("change")){abuse=openControlled;}break;caseeXULCommand:abuse=openControlled;break;default:break;}}break;caseeKeyboardEventClass:if(aEvent->IsTrusted()){uint32_tkey=aEvent->AsKeyboardEvent()->mKeyCode;switch(aEvent->mMessage){caseeKeyPress:// return key on focused button. see note at eMouseClick.if(key==NS_VK_RETURN){abuse=openAllowed;}elseif(PopupAllowedForEvent("keypress")){abuse=openControlled;}break;caseeKeyUp:// space key on focused button. see note at eMouseClick.if(key==NS_VK_SPACE){abuse=openAllowed;}elseif(PopupAllowedForEvent("keyup")){abuse=openControlled;}break;caseeKeyDown:if(PopupAllowedForEvent("keydown")){abuse=openControlled;}break;default:break;}}break;caseeTouchEventClass:if(aEvent->IsTrusted()){switch(aEvent->mMessage){caseeTouchStart:if(PopupAllowedForEvent("touchstart")){abuse=openControlled;}break;caseeTouchEnd:if(PopupAllowedForEvent("touchend")){abuse=openControlled;}break;default:break;}}break;caseeMouseEventClass:if(aEvent->IsTrusted()&&aEvent->AsMouseEvent()->button==WidgetMouseEvent::eLeftButton){switch(aEvent->mMessage){caseeMouseUp:if(PopupAllowedForEvent("mouseup")){abuse=openControlled;}break;caseeMouseDown:if(PopupAllowedForEvent("mousedown")){abuse=openControlled;}break;caseeMouseClick:/* Click events get special treatment because of their historical status as a more legitimate event handler. If click popups are enabled in the prefs, clear the popup status completely. */if(PopupAllowedForEvent("click")){abuse=openAllowed;}break;caseeMouseDoubleClick:if(PopupAllowedForEvent("dblclick")){abuse=openControlled;}break;default:break;}}break;caseePointerEventClass:if(aEvent->IsTrusted()&&aEvent->AsPointerEvent()->button==WidgetMouseEvent::eLeftButton){switch(aEvent->mMessage){caseePointerUp:if(PopupAllowedForEvent("pointerup")){abuse=openControlled;}break;caseePointerDown:if(PopupAllowedForEvent("pointerdown")){abuse=openControlled;}break;default:break;}}break;caseeFormEventClass:// For these following events only allow popups if they're// triggered while handling user input. See// nsPresShell::HandleEventInternal() for details.if(EventStateManager::IsHandlingUserInput()){switch(aEvent->mMessage){caseeFormSubmit:if(PopupAllowedForEvent("submit")){abuse=openControlled;}break;caseeFormReset:if(PopupAllowedForEvent("reset")){abuse=openControlled;}break;default:break;}}break;default:break;}returnabuse;}// staticvoidEvent::PopupAllowedEventsChanged(){if(sPopupAllowedEvents){free(sPopupAllowedEvents);}nsAdoptingCStringstr=Preferences::GetCString("dom.popup_allowed_events");// We'll want to do this even if str is empty to avoid looking up// this pref all the time if it's not set.sPopupAllowedEvents=ToNewCString(str);}// staticvoidEvent::Shutdown(){if(sPopupAllowedEvents){free(sPopupAllowedEvents);}}// staticCSSIntPointEvent::GetScreenCoords(nsPresContext*aPresContext,WidgetEvent*aEvent,LayoutDeviceIntPointaPoint){if(EventStateManager::sIsPointerLocked){returnEventStateManager::sLastScreenPoint;}if(!aEvent||(aEvent->mClass!=eMouseEventClass&&aEvent->mClass!=eMouseScrollEventClass&&aEvent->mClass!=eWheelEventClass&&aEvent->mClass!=ePointerEventClass&&aEvent->mClass!=eTouchEventClass&&aEvent->mClass!=eDragEventClass&&aEvent->mClass!=eSimpleGestureEventClass)){returnCSSIntPoint(0,0);}// Doing a straight conversion from LayoutDeviceIntPoint to CSSIntPoint// seem incorrect, but it is needed to maintain legacy functionality.WidgetGUIEvent*guiEvent=aEvent->AsGUIEvent();if(!aPresContext||!(guiEvent&&guiEvent->mWidget)){returnCSSIntPoint(aPoint.x,aPoint.y);}nsPointpt=LayoutDevicePixel::ToAppUnits(aPoint,aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());if(nsIPresShell*ps=aPresContext->GetPresShell()){pt=pt.RemoveResolution(nsLayoutUtils::GetCurrentAPZResolutionScale(ps));}pt+=LayoutDevicePixel::ToAppUnits(guiEvent->mWidget->WidgetToScreenOffset(),aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());returnCSSPixel::FromAppUnitsRounded(pt);}// staticCSSIntPointEvent::GetPageCoords(nsPresContext*aPresContext,WidgetEvent*aEvent,LayoutDeviceIntPointaPoint,CSSIntPointaDefaultPoint){CSSIntPointpagePoint=Event::GetClientCoords(aPresContext,aEvent,aPoint,aDefaultPoint);// If there is some scrolling, add scroll info to client point.if(aPresContext&&aPresContext->GetPresShell()){nsIPresShell*shell=aPresContext->GetPresShell();nsIScrollableFrame*scrollframe=shell->GetRootScrollFrameAsScrollable();if(scrollframe){pagePoint+=CSSIntPoint::FromAppUnitsRounded(scrollframe->GetScrollPosition());}}returnpagePoint;}// staticCSSIntPointEvent::GetClientCoords(nsPresContext*aPresContext,WidgetEvent*aEvent,LayoutDeviceIntPointaPoint,CSSIntPointaDefaultPoint){if(EventStateManager::sIsPointerLocked){returnEventStateManager::sLastClientPoint;}if(!aEvent||(aEvent->mClass!=eMouseEventClass&&aEvent->mClass!=eMouseScrollEventClass&&aEvent->mClass!=eWheelEventClass&&aEvent->mClass!=eTouchEventClass&&aEvent->mClass!=eDragEventClass&&aEvent->mClass!=ePointerEventClass&&aEvent->mClass!=eSimpleGestureEventClass)||!aPresContext||!aEvent->AsGUIEvent()->mWidget){returnaDefaultPoint;}nsIPresShell*shell=aPresContext->GetPresShell();if(!shell){returnCSSIntPoint(0,0);}nsIFrame*rootFrame=shell->GetRootFrame();if(!rootFrame){returnCSSIntPoint(0,0);}nsPointpt=nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,aPoint,rootFrame);returnCSSIntPoint::FromAppUnitsRounded(pt);}// staticCSSIntPointEvent::GetOffsetCoords(nsPresContext*aPresContext,WidgetEvent*aEvent,LayoutDeviceIntPointaPoint,CSSIntPointaDefaultPoint){if(!aEvent->mTarget){returnGetPageCoords(aPresContext,aEvent,aPoint,aDefaultPoint);}nsCOMPtr<nsIContent>content=do_QueryInterface(aEvent->mTarget);if(!content||!aPresContext){returnCSSIntPoint(0,0);}nsCOMPtr<nsIPresShell>shell=aPresContext->GetPresShell();if(!shell){returnCSSIntPoint(0,0);}shell->FlushPendingNotifications(FlushType::Layout);nsIFrame*frame=content->GetPrimaryFrame();if(!frame){returnCSSIntPoint(0,0);}nsIFrame*rootFrame=shell->GetRootFrame();if(!rootFrame){returnCSSIntPoint(0,0);}CSSIntPointclientCoords=GetClientCoords(aPresContext,aEvent,aPoint,aDefaultPoint);nsPointpt=CSSPixel::ToAppUnits(clientCoords);if(nsLayoutUtils::TransformPoint(rootFrame,frame,pt)==nsLayoutUtils::TRANSFORM_SUCCEEDED){pt-=frame->GetPaddingRectRelativeToSelf().TopLeft();returnCSSPixel::FromAppUnitsRounded(pt);}returnCSSIntPoint(0,0);}// To be called ONLY by Event::GetType (which has the additional// logic for handling user-defined events).// staticconstchar*Event::GetEventName(EventMessageaEventType){switch(aEventType){#define MESSAGE_TO_EVENT(name_, _message, _type, _struct) \ case _message: return #name_;#include"mozilla/EventNameList.h"#undef MESSAGE_TO_EVENTdefault:break;}// XXXldb We can hit this case for WidgetEvent objects that we didn't// create and that are not user defined events since this function and// SetEventType are incomplete. (But fixing that requires fixing the// arrays in nsEventListenerManager too, since the events for which// this is a problem generally *are* created by Event.)returnnullptr;}boolEvent::DefaultPrevented(CallerTypeaCallerType)const{NS_ENSURE_TRUE(mEvent,false);// If preventDefault() has never been called, just return false.if(!mEvent->DefaultPrevented()){returnfalse;}// If preventDefault() has been called by content, return true. Otherwise,// i.e., preventDefault() has been called by chrome, return true only when// this is called by chrome.returnmEvent->DefaultPreventedByContent()||aCallerType==CallerType::System;}doubleEvent::TimeStampImpl()const{if(!sReturnHighResTimeStamp){returnstatic_cast<double>(mEvent->mTime);}if(mEvent->mTimeStamp.IsNull()){return0.0;}if(mIsMainThreadEvent){if(NS_WARN_IF(!mOwner)){return0.0;}nsCOMPtr<nsPIDOMWindowInner>win=do_QueryInterface(mOwner);if(NS_WARN_IF(!win)){return0.0;}Performance*perf=win->GetPerformance();if(NS_WARN_IF(!perf)){return0.0;}returnperf->GetDOMTiming()->TimeStampToDOMHighRes(mEvent->mTimeStamp);}workers::WorkerPrivate*workerPrivate=workers::GetCurrentThreadWorkerPrivate();MOZ_ASSERT(workerPrivate);returnworkerPrivate->TimeStampToDOMHighRes(mEvent->mTimeStamp);}doubleEvent::TimeStamp()const{returnnsRFPService::ReduceTimePrecisionAsMSecs(TimeStampImpl());}boolEvent::GetPreventDefault()const{nsCOMPtr<nsPIDOMWindowInner>win(do_QueryInterface(mOwner));if(win){if(nsIDocument*doc=win->GetExtantDoc()){doc->WarnOnceAbout(nsIDocument::eGetPreventDefault);}}// GetPreventDefault() is legacy and Gecko specific method. Although,// the result should be same as defaultPrevented, we don't need to break// backward compatibility of legacy method. Let's behave traditionally.returnDefaultPrevented();}NS_IMETHODIMPEvent::GetPreventDefault(bool*aReturn){NS_ENSURE_ARG_POINTER(aReturn);*aReturn=GetPreventDefault();returnNS_OK;}NS_IMETHODIMPEvent::GetDefaultPrevented(bool*aReturn){NS_ENSURE_ARG_POINTER(aReturn);// This method must be called by only event handlers implemented by C++.// Then, the handlers must handle default action. So, this method don't need// to check if preventDefault() has been called by content or chrome.*aReturn=DefaultPrevented();returnNS_OK;}NS_IMETHODIMP_(void)Event::Serialize(IPC::Message*aMsg,boolaSerializeInterfaceType){if(aSerializeInterfaceType){IPC::WriteParam(aMsg,NS_LITERAL_STRING("event"));}nsStringtype;GetType(type);IPC::WriteParam(aMsg,type);IPC::WriteParam(aMsg,Bubbles());IPC::WriteParam(aMsg,Cancelable());IPC::WriteParam(aMsg,IsTrusted());IPC::WriteParam(aMsg,Composed());// No timestamp serialization for now!}NS_IMETHODIMP_(bool)Event::Deserialize(constIPC::Message*aMsg,PickleIterator*aIter){nsStringtype;NS_ENSURE_TRUE(IPC::ReadParam(aMsg,aIter,&type),false);boolbubbles=false;NS_ENSURE_TRUE(IPC::ReadParam(aMsg,aIter,&bubbles),false);boolcancelable=false;NS_ENSURE_TRUE(IPC::ReadParam(aMsg,aIter,&cancelable),false);booltrusted=false;NS_ENSURE_TRUE(IPC::ReadParam(aMsg,aIter,&trusted),false);boolcomposed=false;NS_ENSURE_TRUE(IPC::ReadParam(aMsg,aIter,&composed),false);InitEvent(type,bubbles,cancelable);SetTrusted(trusted);SetComposed(composed);returntrue;}NS_IMETHODIMP_(void)Event::SetOwner(EventTarget*aOwner){mOwner=nullptr;if(!aOwner){return;}nsCOMPtr<nsINode>n=do_QueryInterface(aOwner);if(n){mOwner=n->OwnerDoc()->GetScopeObject();return;}nsCOMPtr<nsPIDOMWindowInner>w=do_QueryInterface(aOwner);if(w){mOwner=do_QueryInterface(w);return;}nsCOMPtr<DOMEventTargetHelper>eth=do_QueryInterface(aOwner);if(eth){mOwner=eth->GetParentObject();return;}#ifdef DEBUGnsCOMPtr<nsPIWindowRoot>root=do_QueryInterface(aOwner);MOZ_ASSERT(root,"Unexpected EventTarget!");#endif}// staticnsIContent*Event::GetShadowRelatedTarget(nsIContent*aCurrentTarget,nsIContent*aRelatedTarget){if(!aCurrentTarget||!aRelatedTarget){returnnullptr;}// Walk up the ancestor node trees of the related target until// we encounter the node tree of the current target in order// to find the adjusted related target. Walking up the tree may// not find a common ancestor node tree if the related target is in// an ancestor tree, but in that case it does not need to be adjusted.ShadowRoot*currentTargetShadow=aCurrentTarget->GetContainingShadow();if(!currentTargetShadow){returnnullptr;}nsIContent*relatedTarget=aCurrentTarget;while(relatedTarget){ShadowRoot*ancestorShadow=relatedTarget->GetContainingShadow();if(currentTargetShadow==ancestorShadow){returnrelatedTarget;}// Didn't find the ancestor tree, thus related target does not have to// adjusted.if(!ancestorShadow){returnnullptr;}relatedTarget=ancestorShadow->GetHost();}returnnullptr;}voidEvent::GetWidgetEventType(WidgetEvent*aEvent,nsAString&aType){if(!aEvent->mSpecifiedEventTypeString.IsEmpty()){aType=aEvent->mSpecifiedEventTypeString;return;}constchar*name=GetEventName(aEvent->mMessage);if(name){CopyASCIItoUTF16(name,aType);return;}elseif(aEvent->mMessage==eUnidentifiedEvent&&aEvent->mSpecifiedEventType){// Remove "on"aType=Substring(nsDependentAtomString(aEvent->mSpecifiedEventType),2);aEvent->mSpecifiedEventTypeString=aType;return;}aType.Truncate();}NS_IMETHODIMPEvent::GetCancelBubble(bool*aCancelBubble){NS_ENSURE_ARG_POINTER(aCancelBubble);*aCancelBubble=CancelBubble();returnNS_OK;}NS_IMETHODIMPEvent::SetCancelBubble(boolaCancelBubble){if(aCancelBubble){mEvent->StopPropagation();}returnNS_OK;}}// namespace dom}// namespace mozillausingnamespacemozilla;usingnamespacemozilla::dom;already_AddRefed<Event>NS_NewDOMEvent(EventTarget*aOwner,nsPresContext*aPresContext,WidgetEvent*aEvent){RefPtr<Event>it=newEvent(aOwner,aPresContext,aEvent);returnit.forget();}